package es.uji.viselab.image.camera;

import es.uji.viselab.math.Matrix4;
import es.uji.viselab.math.Vector3;

/**
 * Create a catalog of cameras with data about their parameters, that is: width
 * and height of the image (in pixels), the focal distance (in meters) and the
 * size of the pixel (in meters) <br>
 * Also, each of the camera has a specific pose, that is the position and
 * orientation once has attached to a end-effector.
 * 
 * @author r.esteller-curto
 * 
 */
public enum CameraCatalog {

	VIRTUALCAMERA("Virtual Eye-on-hand 640x480 6mm") {

		@Override
		void init() {
			imageWidth = 640;
			imageHeight = 480;
			focalDistance = 0.006;
			pixelSize = 7.1e-6;

			Matrix4 translation = new Matrix4();
			translation.set(new Vector3(0.0, 0.0, 0.2));

			double[][] simetryYvector = { { 1d, 0d, 0d, 0d }, { 0d, -1d, 0d, 0d },
					{ 0d, 0d, 1d, 0d }, { 0d, 0d, 0d, 1d } };
			Matrix4 simetryY = new Matrix4(simetryYvector);

			pose = new Matrix4();
			Matrix4 rotationZ = new Matrix4();
			rotationZ.rotZ(Math.PI / 2);
			pose.mul(simetryY, rotationZ);
			pose.mul(translation, pose);
		}
	},
	NETGMBH1394_6MM("Net 1394 eye-on-hand 640x480 6mm") {
		@Override
		void init() {
			imageWidth = 640;
			imageHeight = 480;
			focalDistance = 0.006; // meters
			pixelSize = 7.1e-6; // meters
			// focal distance as
			// http://www.vision.caltech.edu/bouguetj/calib_doc/
			// is 845 mm that is focalDistance/pixelSize

			Matrix4 translation = new Matrix4();
			translation.set(new Vector3(0.0, 0.0, 0.2));
			//translation.set(new Vector3(0.0, 0.0, 0.0));

			double[][] simetryYvector = { { 1d, 0d, 0d, 0d }, { 0d, -1d, 0d, 0d },
					{ 0d, 0d, 1d, 0d }, { 0d, 0d, 0d, 1d } };
			Matrix4 simetryY = new Matrix4(simetryYvector);

			pose = new Matrix4();
			Matrix4 rotationZ = new Matrix4();
			rotationZ.rotZ(-Math.PI / 4);
			pose.mul(simetryY, rotationZ);
			pose.mul(translation, pose);
		}
	},
	KINECT("Kinect") {
		@Override
		void init() {
		}
	};

	protected String name;
	protected double imageWidth;
	protected double imageHeight;
	protected double focalDistance;
	protected double pixelSize;
	protected Matrix4 pose;

	CameraCatalog(String name) {
		this.name = name;
		init();
	}

	abstract void init();

	/** 
	 * Public name of the camera
	 * 
	 * @returns name
	 */
	public String toString() {
		return this.name;
	}

	/**
	 * Returs the real focal distance (meters) of the camera divided by the
	 * pixel size (meters per pixel). The result is therefore the focal distance
	 * in pixels, which is useful because any other distance on the camera frame is always in pixels
	 * 
	 * @return focal distance in pixels
	 */
	public double getFocalDistanceCorrected() {
		return focalDistance / pixelSize;
	}

	/**
	 * Pose of the camera; position and orientation relative to any place where
	 * can be attached
	 * 
	 * @return the Homography matrix of the pose
	 * @see Matrix4
	 */
	public Matrix4 getPose() {
		return pose;
	}

	/**
	 * Image width in pixels of the camera
	 * 
	 * @return the image width in pixels
	 */
	public double getImageWidth() {
		return imageWidth;
	}

	/**
	 * Image height in pixels of the camera
	 * 
	 * @return image height in pixels
	 */
	public double getImageHeight() {
		return imageHeight;
	}

	public boolean isHandOnEyeCamera() {
		return true;
	}

}
